package club.kynb.mall.application.service;

import club.kynb.mall.application.constant.AuthConst;
import club.kynb.mall.application.context.AuthenticationContext;
import club.kynb.mall.application.flow.user.*;
import club.kynb.mall.application.model.model.command.*;
import club.kynb.mall.application.model.model.dto.TokenDTO;
import club.kynb.mall.application.model.model.vo.LoginResultVO;
import club.kynb.mall.application.repository.AuthRepository;
import club.kynb.mall.user.api.IUserService;
import club.kynb.mall.user.model.dto.UserDTO;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.pizza.event.publish.EventBus;
import org.pizza.pattern.filter.FilterChain;
import org.pizza.pattern.filter.FilterChainFactory;
import org.springframework.stereotype.Service;


/**
 * @author kynb_club@163.com
 * @since 2021/6/20 3:47 下午
 */
@Slf4j
@Service
@AllArgsConstructor
public class AuthenticationApplicationService {
    public final IUserService iUserService;
    public final EventBus eventBus;
    public final AuthRepository authRepository;

    public LoginResultVO pwdLogin(PwdAuthenticationCommand command) {
        AuthenticationContext authenticationContext = this.initContext(command);
        FilterChain<AuthenticationContext> filterChain = this.buildPwdLoginFilterChain();
        filterChain.doFilter(authenticationContext);
        final TokenDTO token = authenticationContext.getToken();
        final UserDTO user = authenticationContext.getUser();
        return this.buildLoginResult(token, user);
    }


    private FilterChain<AuthenticationContext> buildPwdLoginFilterChain() {
        return FilterChainFactory.buildFilterChain(
                CheckAuthFailedCountFilter.class
                , CheckCaptchaFilter.class
                , CheckPasswordFilter.class
                , BuildTokenFilter.class
                , AuthSuccessFilter.class
        );
    }

    private AuthenticationContext initContext(AuthenticationCommand command) {
        AuthenticationContext authenticationContext = new AuthenticationContext();
        authenticationContext.setAuthenticationCommand(command);
        return authenticationContext;
    }


    public void logout(LogoutCommand command) {
        String accessToken = command.getToken();
        authRepository.deleteToken(String.format("%s:%s", AuthConst.TOKEN_PREFIX, accessToken));
    }

    public LoginResultVO smsLogin(SmsAuthenticationCommand command) {
        AuthenticationContext authenticationContext = this.initContext(command);
        FilterChain<AuthenticationContext> filterChain = this.buildSmsLoginFilterChain();
        filterChain.doFilter(authenticationContext);
        final TokenDTO token = authenticationContext.getToken();
        final UserDTO user = authenticationContext.getUser();
        return this.buildLoginResult(token, user);
    }

    private LoginResultVO buildLoginResult(TokenDTO token, UserDTO userDTO) {
        final LoginResultVO loginResultVO = new LoginResultVO();
        loginResultVO.setUserId(String.valueOf(userDTO.getId()));
        loginResultVO.setUserName(userDTO.getNickname());
        loginResultVO.setAccessToken(token);
        return loginResultVO;
    }

    private FilterChain<AuthenticationContext> buildSmsLoginFilterChain() {
        return FilterChainFactory.buildFilterChain(
                CheckAuthFailedCountFilter.class
                , CheckSmsVerificationCodeFilter.class
                , BuildTokenFilter.class
                , AuthSuccessFilter.class
        );
    }

    public void findPwd(SmsFindPasswordCommand command) {
        AuthenticationContext authenticationContext = this.initContext(command);
        FilterChain<AuthenticationContext> filterChain = this.buildSmsFindPwdFilterChain();
        filterChain.doFilter(authenticationContext);
    }

    private FilterChain<AuthenticationContext> buildSmsFindPwdFilterChain() {
        return FilterChainFactory.buildFilterChain(
                CheckSmsVerificationCodeFilter.class,
                UserUpdatePwdFilter.class
        );
    }
}
